package cn.cdu.basics.utils;

import cn.hutool.http.HttpUtil;
import cn.cdu.data.utils.NullUtils;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.Operation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Objects;

/**
 * IP地址工具类
 */
@Slf4j
@Component
public class IpInfoUtil {

    @Value("${tencent.map.key}")
    private String key;

    @Value("${tencent.map.url}")
    private String txdtUrlPre;

    private static final String IP_HEADER_PRE_ONE = "x-forwarded-for";

    private static final String IP_HEADER_PRE_TWO = "Proxy-Client-IP";

    private static final String IP_HEADER_PRE_THREE = "WL-Proxy-Client-IP";

    private static final String IP_HEADER_NONE = "unknown";

    private static final String IP_HEADER_LOCAL_HOST = "127.0.0.1";

    private static final String IP_HEADER_LOCAL_LONG_HOST = "0:0:0:0:0:0:0:1";

    private static final int MAX_RETRIES = 3;
    private static final long RETRY_DELAY_MS = 1000;

    @Operation(summary = "查询IP地址的区县")
    public String getIpCity(HttpServletRequest request) {
        String ip = getRequestIpAddress(request);
        if (isLocalIp(ip)) {
            log.debug("Local IP detected: {}", ip);
            return "本地";
        }
        return getIpCityWithRetry(ip);
    }

    private boolean isLocalIp(String ip) {
        return IP_HEADER_LOCAL_HOST.equals(ip) || 
               IP_HEADER_LOCAL_LONG_HOST.equals(ip) ||
               ip.startsWith("192.168.") ||
               ip.startsWith("10.") ||
               ip.startsWith("172.16.") ||
               ip.startsWith("172.17.") ||
               ip.startsWith("172.18.") ||
               ip.startsWith("172.19.") ||
               ip.startsWith("172.20.") ||
               ip.startsWith("172.21.") ||
               ip.startsWith("172.22.") ||
               ip.startsWith("172.23.") ||
               ip.startsWith("172.24.") ||
               ip.startsWith("172.25.") ||
               ip.startsWith("172.26.") ||
               ip.startsWith("172.27.") ||
               ip.startsWith("172.28.") ||
               ip.startsWith("172.29.") ||
               ip.startsWith("172.30.") ||
               ip.startsWith("172.31.");
    }

    private String getIpCityWithRetry(String ip) {
        for (int i = 0; i < MAX_RETRIES; i++) {
            try {
                String url = txdtUrlPre + key + "&ip=" + ip;
                log.debug("Querying IP location for IP: {}", ip);
                
                String response = HttpUtil.get(url, 3000);
                JsonObject objectResult = JsonParser.parseString(response).getAsJsonObject();
                
                String status = objectResult.get("status").getAsString();
                if (Objects.equals(status, "0")) {
                    JsonObject adInfo = objectResult.get("result").getAsJsonObject().get("ad_info").getAsJsonObject();
                    String nationStr = adInfo.get("nation").getAsString();
                    String provinceStr = adInfo.get("province").getAsString();
                    String cityStr = adInfo.get("city").getAsString();
                    String districtStr = adInfo.get("district").getAsString();
                    
                    String resultStr;
                    if (!NullUtils.isNull(nationStr) && NullUtils.isNull(provinceStr)) {
                        resultStr = nationStr;
                    } else {
                        resultStr = provinceStr;
                        if (!NullUtils.isNull(cityStr)) {
                            resultStr += "-" + cityStr;
                        }
                        if (!NullUtils.isNull(districtStr)) {
                            resultStr += "-" + districtStr;
                        }
                    }
                    log.debug("Successfully queried IP location: {}", resultStr);
                    return resultStr;
                } else {
                    String message = objectResult.has("message") ? objectResult.get("message").getAsString() : "Unknown error";
                    log.warn("IP location query failed with status: {}, message: {}", status, message);
                    
                    if ("121".equals(status)) {
                        log.error("Invalid API key or API access denied");
                        return "未知地区";
                    }
                }
            } catch (Exception e) {
                log.warn("IP location query attempt {} failed: {}", i + 1, e.getMessage());
                if (i < MAX_RETRIES - 1) {
                    try {
                        Thread.sleep(RETRY_DELAY_MS);
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                }
            }
        }
        log.warn("All IP location query attempts failed for IP: {}", ip);
        return "未知地区";
    }

    @Operation(summary = "查询请求的IP地址")
    public String getRequestIpAddress(HttpServletRequest request) {
        String ipAddress = request.getHeader(IP_HEADER_PRE_ONE);
        if (ipAddress == null || ipAddress.length() < 1 || IP_HEADER_NONE.equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader(IP_HEADER_PRE_TWO);
        }
        if (ipAddress == null || ipAddress.length() < 1 || IP_HEADER_NONE.equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader(IP_HEADER_PRE_THREE);
        }
        if (ipAddress == null || ipAddress.length() < 1 || IP_HEADER_NONE.equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getRemoteAddr();
            if (Objects.equals(IP_HEADER_LOCAL_HOST, ipAddress)) {
                InetAddress inetAddress = null;
                try {
                    inetAddress = InetAddress.getLocalHost();
                } catch (UnknownHostException exception) {
                    log.error("Failed to get local host address", exception);
                }
                if (inetAddress != null) {
                    ipAddress = inetAddress.getHostAddress();
                }
            }
        }
        if (ipAddress != null && ipAddress.length() > 15) {
            if (ipAddress.indexOf(",") > 0) {
                ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
            }
        }
        if (Objects.equals(IP_HEADER_LOCAL_LONG_HOST, ipAddress)) {
            ipAddress = IP_HEADER_LOCAL_HOST;
        }
        log.debug("Resolved IP address: {}", ipAddress);
        return ipAddress;
    }
}
